using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using zijian666.Core.Abstractions;
using zijian666.DI;

namespace UnitTests;

[TestClass]
public class 装配测试
{
    [TestMethod]
    public void 全局装配()
    {
        var services = new ServiceCollection()
            .AddTransient<MyService1>(p => p.Autowired(() => new MyService1()))
            .AddSingleton<MyService1>()
            .AddSingleton<MyService2>()
            .AddSingleton<MyService3>()
            .AddSingleton<IFeature, MyService1>()
            .AddSingleton<IFeature, MyService2>()
            .AddSingleton<IFeature, MyService3>()
            .AddAutowired()
            .BuildServiceProvider();


        var mysrv = services.GetService<MyService1>();

        Assert.IsNotNull(mysrv.MyService2);
        Assert.AreEqual(mysrv.MyService2.MyService1, mysrv);

        Assert.IsNotNull(mysrv.MyService3);

        Assert.AreEqual(mysrv.MyService3.MyService, mysrv.MyService3);
        Assert.IsNotNull(mysrv.MyService3.MyServices);
        Assert.AreEqual(mysrv.MyService3.MyServices.Count(), 3);

    }


    class MyService1 : IFeature
    {
        [Autowired]
        public MyService2 MyService2;
        [Autowired]
        public MyService3 MyService3;
    }

    class MyService2 : IFeature
    {
        [Autowired]
        public readonly MyService1 MyService1;
    }


    class MyService3 : IFeature
    {

        [Autowired(serviceType: typeof(MyService3))]
        public IFeature MyService;

        [Autowired]
        public IEnumerable<IFeature> MyServices;
    }
    class MyService4
    {
        [Autowired]
        public SingletonServiceProvider ServiceProvider;
    }
    class MyService5
    {
        [Autowired]
        public ScopedServiceProvider ServiceProvider;
    }

    [TestMethod]
    public void 范围装配()
    {
        var root = new ServiceCollection()
            .AddTransient<MyService1>(p => p.Autowired(() => new MyService1()))
            .AddSingleton<MyService1>()
            .AddSingleton<MyService2>()
            .AddSingleton<MyService3>()
            .AddSingleton<IFeature, MyService1>()
            .AddSingleton<IFeature, MyService2>()
            .AddSingleton<IFeature, MyService3>()
            .AddSingleton<MyService4>()
            .AddScoped<MyService5>()
            .AddAutowired()
            .BuildServiceProvider();

        using var scope = root.CreateScope();
        var services = scope.ServiceProvider;

        var mysrv = services.GetService<MyService1>();

        Assert.IsNotNull(mysrv.MyService2);
        Assert.AreEqual(mysrv.MyService2.MyService1, mysrv);

        Assert.IsNotNull(mysrv.MyService3);

        Assert.AreEqual(mysrv.MyService3.MyService, mysrv.MyService3);
        Assert.IsNotNull(mysrv.MyService3.MyServices);
        Assert.AreEqual(mysrv.MyService3.MyServices.Count(), 3);

        var s5 = services.GetService<MyService5>().ServiceProvider;
        var s4 = services.GetService<MyService4>().ServiceProvider;

        Assert.IsNotNull(s4);
        Assert.IsNotNull(s5);
        Assert.AreEqual(s5, services);
        Assert.AreNotEqual<IServiceProvider>(s5, s4);
    }


    abstract class MyService6Base
    {
        [Autowired]
        public readonly ILogger Logger;
    }

    [Component(typeof(MyService6Base))]
    class MyService6 : MyService6Base
    {

    }

    [TestMethod]
    public void 自动装配Logger()
    {
        var services = new ServiceCollection()
            .AddLogging()
            .AddSingleton<MyService6Base, MyService6>()
            .AddAutowired()
            .BuildServiceProvider();
        var service = services.GetService<MyService6Base>();
        Assert.IsNotNull(service);
        Assert.IsNotNull(service.Logger);
        var type = service.Logger.GetType();
        Assert.AreEqual(typeof(Logger<MyService6>), type);
    }


    [Component(Lifetime = ServiceLifetime.Singleton)]
    class MyServiceSingleton
    {
        [Autowired]
        public ScopedServiceProvider ServiceProvider;
    }

    [TestMethod]
    public void ServiceProvider()
    {
        {
            var root = new ServiceCollection()
                          .AddComponents()
                          .AddAutowired()
                          .BuildServiceProvider();

            using var scope = root.CreateScope();
            var services = scope.ServiceProvider;

            var singleton = services.GetService<MyServiceSingleton>();

            Assert.IsFalse(singleton!.ServiceProvider.Equals(services));
        }

        {
            var root = new ServiceCollection()
                          .AddComponents()
                          .AddAutowired()
                          .BuildServiceProvider();

            using var scope = root.CreateScope();
            var services = scope.ServiceProvider;

            var singleton = services.GetServiceWithScope<MyServiceSingleton>();
            Assert.IsTrue(singleton!.ServiceProvider.Equals(services));
        }

    }


}
